#!/usr/local/bin/python
# Rob Dennis - Lurchington Q. Delacroix
# Keasby - TV renamer
# Project Homepage: http://code.google.com/p/keasby/

#---Python modules

from os.path import join as pjoin
import unittest
import logging

class KeasbyTestCase(unittest.TestCase):
    """
    Intended to the baseclass for all test-cases. Specifies Keasby-specific
    parameters to test against. As well as specific assertions
    """

    def __init__(self, *args, **kwargs):
        """
        Initializes Keasby-specific information
        """

        self._initialize_tvepisodes()
        #parent init
        unittest.TestCase.__init__(self, *args, **kwargs)

    def _initialize_tvepisodes(self):
        """
        Initialzing the TvEpisode lists to check against
        """

        #Tuples for the simple creation of more test data
        #Will be mapped to the following keys names, in order:
        key_names = ("showname", "season_number", "episode_number", "path")

        #This list is intended to give a good spread of possible input
        value_list = [
                        #Normal, well formatted case
                        ("Scrubs", 1, 1,
                            pjoin("Scrubs", "Season 01", "Scrubs-S01E01.avi")),

                        #Grouped episode case
                        ("Avatar The Last Airbender", 1, [1,2],
                            pjoin("Avatar The Last Airbender",
                                    "Season 1", "Avatar s01e01-02.avi")),

                        #Abbreviated name case
                        ("The Venture Bros.", 1, 1,
                            pjoin("The Venture Bros.", "Season 1", "101.avi")),

                        #Number in showname case
                        ("30 Rock", 1, 1,
                            pjoin("30 Rock", "Season 1", "30rock - 101.avi")),

                        #Year in showname case
                        ("Battlestar Galactica (2003)", 4, 1,
                            pjoin("Battlestar Galactica (2003)",
                                    "battlestar.galactica.401.avi")),

                        #Grouped numbers case
                        ("South Park", 1, 1,
                            pjoin("South Park","101.avi"))
                        ]

        self.expected = [dict(zip(key_names, tv_ep_values))
                            for tv_ep_values in value_list]

        self.media_list = [tv_ep.get("path") for tv_ep in self.expected]

#---Extra Assertions

    def assertLog(self,
                    expression,
                    fail_message=None,
                    pass_message=None,
                    assertion=None,
                    pass_log=logging.debug):
        """
        if the assertion fails for the given expression, log the
        given fail message with the given logging expression.
        Else, return True. If assert remain None, defaults
        to self.assertTrue
        """

        if assertion is None:
            assertion = self.assertTrue

        assertion(expression,fail_message)

        if pass_message:
            pass_log(pass_message)

    def assertDictEquals(self,left_dict,right_dict):
        """
        Takes in two dictionaries, and compares them key by key
        """

        self.assertLog(isinstance(left_dict,dict),
                        fail_message="1st argument not a dict: %s, value=%s"%\
                                        (type(left_dict),left_dict))
        self.assertLog(isinstance(right_dict,dict),
                        fail_message="2nd argument not a dict: %s, value=%s"%\
                                        (type(right_dict),right_dict))
        try:
            self.assertEquals(len(left_dict),len(right_dict))

            logging.debug("left dictionary argument: %s",left_dict)
            logging.debug("right dictionary argument: %s",right_dict)

            for left_key,left_value in left_dict.iteritems():
                self.assertLog(left_value == right_dict.get(left_key),
                    "for key: %s, %s!=%s"%(left_key,left_value,
                                        right_dict.get(left_key)))

        except AssertionError:
            #catching errors in order to pre-pend the dictionary values

            import sys
            #hack - this index should really have been a string, but it's:
            #AssertionError(error_message) instead of error_message
            error_message = sys.exc_info()[1].message

            traceback = sys.exc_info()[2]

            _fail = "-----".join(["%s != %s"%(left_dict,right_dict),
                                    error_message])

            raise AssertionError,_fail,traceback

    def assertDictSubset(self,subdict,fulldict):
        """
        Returns True if, for all keys in subdict, the values of subdict
        and fulldict are equal
        """

        self.assertLog(isinstance(subdict,dict),
                        fail_message="1st argument not a dict: %s, value=%s"%\
                                        (type(subdict),subdict))
        self.assertLog(isinstance(fulldict,dict),
                        fail_message="2nd argument not a dict: %s, value=%s"%\
                                        (type(fulldict),fulldict))

        try:
            cut_items = [(key,fulldict[key]) for key in subdict.iterkeys()]
        except KeyError, error_message:
            raise AssertionError("key %s not found. %s != %s"%(error_message,
                                                                    subdict,
                                                                    fulldict))
        cut_fulldict = dict(cut_items)

        self.assertDictEquals(subdict,cut_fulldict)

    def __test_sanity(self):
        """
        Ensure that basic initialization occurs for the base Unit Test
        """

        for expected_values in self.expected:
            self.assertTrue(expected_values)
            logging.debug(expected_values)

        for media_file in self.media_list:
            self.assertTrue(media_file)
            logging.debug(media_file)

        self.assertLog(True)
        self.assertLog(False, assertion=self.assertFalse)
        self.assertLog(True, pass_message="passed test")
        # uncomment to test the fail condition
        ##self.assertLog(False, fail_message="did not pass test")